package com.fasteat.netty.handler;

import com.alibaba.fastjson.JSON;
import com.fasteat.common.util.FileUtil;
import com.fasteat.enums.MsgAction;
import com.fasteat.enums.MsgType;
import com.fasteat.netty.dto.ChatMsg;
import com.fasteat.netty.dto.DataContent;
import com.fasteat.vo.User;
import com.fasteat.service.UserService;
import com.fasteat.util.RedisUtil;
import com.fasteat.util.ServiceRecord;
import com.fasteat.util.SpringUtil;
import com.fasteat.util.UserChannelMap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.Map;

/**
 * 私聊
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    //注入redisUtil
    RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        //获取客户端消息
        String text = textWebSocketFrame.text();
        DataContent dataContent = JSON.parseObject(text, DataContent.class);
        int action = dataContent.getAction();
        ChatMsg chatMsg = dataContent.getChatMsg();
        Channel channel = channelHandlerContext.channel();

        //判断消息类型，根据不同的类型来处理不同的业务
        switch (action) {
            case MsgAction.CONNECT: {
                //把channel 和 userid 关联起来
                String senderId = dataContent.getChatMsg().getSenderId();
                UserChannelMap.put(senderId, channel);
                break;
            }
            //聊天通讯
            case MsgAction.CHAT: {
                String receiverId = chatMsg.getReceiverId();

                Channel receiverChannel = UserChannelMap.getChannel(receiverId);
                // 接收者未上线
                if (receiverChannel == null) {
                    // 将未接收消息放入redis
                    redisUtil.hset(receiverId, chatMsg.getId(), chatMsg);
                } else {
                    //接收者在线，将消息发送
                    receiverChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(chatMsg)));
                }
                break;
            }
            //接收未读消息
            case MsgAction.SIGNED: {
                Map<Object, Object> objects = redisUtil.hmget(chatMsg.getSenderId());
                if (objects != null && objects.size() > 0) {
                    ChannelFuture channelFuture = channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(objects.values())));
                    if(channelFuture.isSuccess()){
                        //签收完毕，删除redis中的未读消息
                        redisUtil.del(chatMsg.getSenderId());
                    }
                }
                break;
            }
            //客服登录后连接
            case MsgAction.SERVICE_UP: {
                //当websocket 第一次连接或重连时，把channel 和 userid 关联起来
                String senderId = dataContent.getChatMsg().getSenderId();
                UserChannelMap.put(senderId, channel);

                //记录已上线客服id
                ServiceRecord.add(senderId);
                break;
            }
            //用户申请接通客服
            case MsgAction.APPLY: {
                try {
                    //获取客服聊天界面信息
                    String serviceId = ServiceRecord.get();
                    UserService userService = SpringUtil.getBean(UserService.class);
                    User userInfo = userService.getUserInfo(serviceId);
                    //将客服信息发送给客户
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(userInfo)));
                }catch (IndexOutOfBoundsException e){
                    channel.writeAndFlush(new TextWebSocketFrame("暂无客服上线，客服在线时间9：00 - 22：00"));
                }

                break;
            }
            //撤回消息
            case MsgAction.WITHDRAW:{
                String receiverId = chatMsg.getReceiverId();
                int type = chatMsg.getType();
                Channel receiverChannel = UserChannelMap.getChannel(receiverId);

                //判断接收者是否在线
                if(receiverChannel == null){
                    //删除redis中对应的id消息
                    if(redisUtil.hasKey(receiverId)){
                        redisUtil.hdel(receiverId, chatMsg.getId());
                    }
                }else {
                    //转发撤回消息
                    receiverChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(chatMsg)));
                }
                break;
            }
            default:
                channel.writeAndFlush(new TextWebSocketFrame("操作错误"));
                break;
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().writeAndFlush(new TextWebSocketFrame("未知错误,将断开连接"));
        //发生异常关闭该连接
        ctx.channel().close();
        //删除对应的映射
        String removedUserId = UserChannelMap.remove(ctx.channel().id());
        //判断是否为客服，是则删除对应记录
        if (ServiceRecord.isService(removedUserId)) {
            ServiceRecord.remove(removedUserId);
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端关闭连接");
        //删除对应的映射
        String removedUserId = UserChannelMap.remove(ctx.channel().id());
        //判断是否为客服，是则删除对应记录
        if (ServiceRecord.isService(removedUserId)) {
            ServiceRecord.remove(removedUserId);
        }
    }
}
